//
// request_handler.cpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <fstream>
#include <sstream>
#include <string>
#include <boost/lexical_cast.hpp>
#include "mime_types.hpp"
#include "reply.hpp"
#include "request.hpp"
#include "request_handler.hpp"
#include "connection.hpp"
#include "server.hpp"
#include "lru_cache_using_boost.hpp"


namespace http {
    namespace server3 {

    request_handler::request_handler():lua_interface_()
        {
        }

        void request_handler::handle_request(boost::shared_ptr<request>& req, boost::shared_ptr<reply>& rep)
        {
            // TODO: change to fast_url_decode
            std::string &request_path = req->uri;
            std::string webqueue_status  = "/webqueue_status";

            // Request path must be absolute and not contain "..".
            if (request_path.empty() || request_path[0] != '/'
                || request_path.find("..") != std::string::npos)
            {
              rep = reply::stock_reply(reply::bad_request);              
            }
            else if(request_path.substr(0, webqueue_status.size()) == webqueue_status)
            {
                handle_status(*rep.get());
            }
            else
            {
#ifdef TEST_SERVER_NO_LUA
            rep->headers.resize(2);
            rep->status = reply::ok;
            rep->headers[0].name = "Content-Length";
            rep->headers[0].value = "0";
            rep->headers[1].name = "Content-Type";
            rep->headers[1].value = "image/gif";
#else
                lua_interface_.do_business_interface(*req.get(),*rep.get());
                rep->add_header("Content-Length",boost::lexical_cast<std::string>(rep->content.length()));
#endif
            }
        }

        void request_handler::handle_status(reply& rep)
        {
            rep.headers.resize(2);
            rep.status = reply::ok;
            rep.content =   "<html>"
                            "<head><title>Status</title></head>"
                            "<body>"
                            "<h3>Number of concurrent connection: ";
            rep.content.append(boost::lexical_cast<std::string>(connection::connection_num));

            rep.content.append(
                             "</h3>"
                             "<h3>Process request rate: ");
            rep.content.append(boost::lexical_cast<std::string>(server::request_rate));

            rep.content.append(
                             "</h3>"
                             "<h3>Cache hit: ");
            rep.content.append(boost::lexical_cast<std::string>(server::cache_hit));

            rep.content.append(
                             "</h3>"
                             "<h3>Cache miss: ");
            rep.content.append(boost::lexical_cast<std::string>(server::cache_miss));

            rep.content.append(
                            "</h3>"
                             "</body>"
                             "</html>");
            rep.headers[0].name = "Content-Length";
            rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size());
            rep.headers[1].name = "Content-Type";
            rep.headers[1].value = "html";
            return;
        }

        bool request_handler::url_decode(const std::string& in, std::string& out)
        {
          out.clear();
          out.reserve(in.size());
          for (std::size_t i = 0; i < in.size(); ++i)
          {
            if (in[i] == '%')
            {
              if (i + 3 <= in.size())
              {
                int value = 0;
                std::istringstream is(in.substr(i + 1, 2));
                if (is >> std::hex >> value)
                {
                  out += static_cast<char>(value);
                  i += 2;
                }
                else
                {
                  return false;
                }
              }
              else
              {
                return false;
              }
            }
            else if (in[i] == '+')
            {
              out += ' ';
            }
            else
            {
              out += in[i];
            }
          }
          return true;
        }
    } // namespace server3
} // namespace http
